<template>
  <!-- <page-container> -->
  <!-- 可拖拽表格 -->
  <el-table
    ref="tableRef"
    :data="tableData"
    border
    row-key="id"
    style="width: 50%"
    :tree-props="{ children: 'child', hasChildren: 'hasChildren' }"
  >
    <el-table-column prop="id" label="ID" width="80" />
    <el-table-column prop="name" label="名称" />
    <el-table-column prop="sort" label="排序值" />
    <el-table-column prop="date" label="日期" />
  </el-table>
  <!-- </page-container> -->
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
import { ElTable, ElTableColumn, ElMessage } from 'element-plus'
// 引入 sortablejs 核心库（关键：拖拽能力的来源）
import Sortable from 'sortablejs'

/**
 * :tree-props="{ children: 'child', hasChildren: 'hasChildren' }" 用来设置子节点的属性
 */

// 1. 定义表格类型和数据
interface TableItem {
  id: number
  name: string
  sort: number
  date: string
  child?: TableItem[]
  hasChildren?: boolean
}
const tableData = ref<TableItem[]>([
  {
    id: 1,
    name: '项目A',
    sort: 1,
    date: '2023-01-01',
    child: [
      {
        id: 6,
        name: '项目A-1',
        sort: 1,
        date: '2023-01-01',
        child: []
      },
      {
        id: 7,
        name: '项目A-2',
        sort: 1,
        date: '2023-01-01',
        child: []
      }
    ]
  },
  { id: 2, name: '项目B', sort: 2, date: '2023-01-02' },
  { id: 3, name: '项目C', sort: 3, date: '2023-01-03' },
  { id: 4, name: '项目D', sort: 4, date: '2023-01-04' },
  { id: 5, name: '项目E', sort: 5, date: '2023-01-05' }
])

// 2. 获取表格 DOM 引用（必须：sortablejs 需要操作表格行 DOM）
const tableRef = ref<InstanceType<typeof ElTable> | null>(null)

// 3. 初始化拖拽功能（在表格渲染完成后执行）
const initSortable = async () => {
  // 等待表格 DOM 完全渲染（nextTick 确保 DOM 已生成，否则tbody 元素可能不存在）
  await nextTick()

  if (!tableRef.value) return

  // 获取表格的 tbody 元素（sortablejs 需绑定到 tbody 上，控制行拖拽）
  const tbody = tableRef.value.$el.querySelector('tbody')
  if (!tbody) return

  // 初始化 Sortable 实例（核心配置）
  new Sortable(tbody, {
    /**
     * 拖拽表格常用的9个属性配置
     */
    // 1. 拖拽时的视觉反馈：行的透明度
    animation: 150,
    // // 2. 限制拖拽方向（默认可自由拖拽，适用于特殊布局）
    // axis: 'y', // 'x' 仅允许水平拖拽，'y' 仅允许垂直拖拽（表格行拖拽常用 'y'）
    // // 3. 是否允许拖拽（全局开关）
    // disabled: false, // true 时禁用所有拖拽功能（可动态修改，如某些权限下禁止拖拽）
    // // 4. 定义哪些元素可以触发拖拽（默认是整个行，可限制为特定子元素）
    // handle: '.drag-handle', // 只有点击带 .drag-handle 类的元素才能触发拖拽（如表格行中的“拖拽图标”）
    // // 5. 定义哪些元素不能被拖拽（排除特定行）
    // filter: '.no-drag', // 带 .no-drag 类的元素无法被拖拽（如“新增行”“标题行”）
    // onFilter: (evt) => {
    //   // 当尝试拖拽被过滤的元素时触发
    //   console.log('该元素禁止拖拽', evt.item)
    // },
    // // 6. 跨列表拖拽配置（多列表之间互相拖拽时生效）
    // group: {
    //   name: 'shared', // 同组名称的列表可以互相拖拽（如“待办”和“已办”列表同组）
    //   pull: true, // 是否允许从其他列表拖入当前列表（true 允许，false 禁止）
    //   put: true // 是否允许当前列表的元素拖出到其他列表（true 允许，false 禁止）
    // },
    // // 7. 拖拽时是否克隆元素（而非移动原元素）
    // clone: false, // true 时拖拽的是原元素的副本，原元素保留（适用于“复制拖拽”场景）
    // // 8. 拖拽时是否跳过空元素（优化多列表拖拽体验）
    // ignore: '.ignore-this', // 忽略带该类的元素，不参与拖拽计算
    // // 9. 触摸设备支持（默认支持，可关闭）
    // touchStartThreshold: 5, // 触摸设备上，滑动多少像素视为拖拽（默认 5px，防止误触）

    /**
     * 拖拽排序的常用的 7个 回调函数
     */
    // 1. 拖拽结束后的回调（核心：处理排序逻辑）
    onEnd: (evt: any) => {
      // evt.oldIndex：拖拽前的行索引（原位置）
      // evt.newIndex：拖拽后的行索引（新位置）
      const oldIndex = evt.oldIndex as number
      const newIndex = evt.newIndex as number

      // 4. 更新表格数据顺序（关键：让表格显示与拖拽一致）
      // 从原位置删除该行数据
      const movedItem = tableData.value.splice(oldIndex, 1)[0]
      // 插入到新位置
      tableData.value.splice(newIndex, 0, movedItem)
      // 重新计算排序值（按新顺序更新 sort 字段）
      tableData.value = tableData.value.map((item, index) => ({
        ...item,
        sort: index + 1 // 排序值从 1 开始
      }))

      // 5. 模拟向后端发送排序请求
      mockUpdateSort(tableData.value)
    }

    // // 2. 开始拖拽时触发（鼠标按下并开始移动的瞬间）
    // onStart: (evt: any) => {
    //   // evt.oldIndex：拖拽前的原始索引
    //   // evt.item：被拖拽的 DOM 元素（表格行<tr>）
    //   console.log(`开始拖拽第 ${evt.oldIndex + 1} 行`)
    //   // 可在此处添加拖拽开始的样式（如高亮被拖拽行）
    //   evt.item.classList.add('dragging-active')
    // },

    // // 3. 拖拽过程中，元素位置发生变化时触发（实时触发）
    // onMove: (evt: any) => {
    //   // evt.dragged：被拖拽的元素
    //   // evt.related：当前拖拽元素下方的元素（可能的目标位置）
    //   // evt.oldIndex / evt.newIndex：实时的旧/新索引
    //   console.log(`从 ${evt.oldIndex + 1} 移动到 ${evt.newIndex + 1}`)
    //   // 可在此处限制拖拽范围（返回 false 可阻止当前位置的移动）
    //   // 例如：禁止拖到索引 0 的位置
    //   // return evt.newIndex !== 0;
    // },

    // // 4. 当元素被添加到当前列表时触发（适用于跨列表拖拽）
    // onAdd: (evt: any) => {
    //   // evt.from：元素原本所在的列表（DOM 元素）
    //   // evt.item：被添加的元素
    //   // 常用于多列表之间的拖拽（如从列表 A 拖到列表 B 时触发）
    //   console.log('元素被添加到当前列表', evt.item)
    // },

    // // 5. 当元素从当前列表被移除时触发（适用于跨列表拖拽）
    // onRemove: (evt: any) => {
    //   // evt.from：元素原本所在的列表（DOM 元素）
    //   // evt.item：被移除的元素
    //   console.log('元素从当前列表移除', evt.item)
    // },

    // // 6. 拖拽被取消时触发（如按下 ESC 键取消拖拽）
    // onCancel: (evt: any) => {
    //   console.log('拖拽被取消')
    //   // 可在此处恢复样式或数据（如回到原始位置）
    // },

    // // 7. 拖拽元素被克隆时触发（适用于配置了 clone: true 的场景）
    // onClone: (evt: any) => {
    //   // evt.clone：被克隆的元素（拖拽时显示的副本）
    //   // 常用于“复制拖拽”（拖拽时保留原元素，生成副本移动）
    //   console.log('元素被克隆', evt.clone)
    //   evt.clone.classList.add('clone-style') // 给克隆元素添加样式
    // }
  })
}

// 4. 模拟向后端发送排序更新请求
const mockUpdateSort = async (data: TableItem[]) => {
  try {
    // 仅传递后端需要的核心字段（id + 新排序值）
    const sortParams = data.map((item) => ({ id: item.id, sort: item.sort }))
    console.log('发送给后端的排序参数：', sortParams)

    // 模拟接口延迟（模拟真实网络请求）
    await new Promise((resolve) => setTimeout(resolve, 800))

    ElMessage.success('排序更新成功')
  } catch (error) {
    console.error('排序更新失败：', error)
    ElMessage.error('排序更新失败，请重试')
    // 可选：请求失败时回滚数据（根据业务需求决定是否开启）
    // tableData.value = originalData // 需要提前保存原数据
  }
}

// 5. 组件挂载后初始化拖拽（确保 DOM 已加载）
onMounted(() => {
  initSortable()
})
</script>

<style scoped>
.drag-table-container {
  width: 90%;
  max-width: 1200px;
  margin: 50px auto;
}

/* 可选：自定义拖拽时的鼠标样式（增强体验） */
.el-table__row {
  cursor: grab;
}
.el-table__row.grabbing {
  cursor: grabbing;
}
</style>
